package com.beyond.core.service;

import java.net.InetSocketAddress;
import java.util.ArrayList;
import java.util.List;

import com.beyond.core.common.EscapeTool;
import com.beyond.core.entity.*;
import com.fasterxml.jackson.core.JsonProcessingException;
import com.fasterxml.jackson.databind.ObjectMapper;

import io.netty.buffer.Unpooled;
import io.netty.channel.ChannelHandlerContext;
import io.netty.channel.socket.DatagramPacket;
import io.netty.util.CharsetUtil;
import lombok.extern.slf4j.Slf4j;

/**
 * 雷达协议包处理线程类
 * 描述：
 *
 * @author wangyingda
 * @date 2021年7月7日
 */
@Slf4j
public class ProtocolService implements Runnable {

    private ChannelHandlerContext ctx;
    private String ip;
    private int port;
    private byte[] content;
    ObjectMapper mapper = new ObjectMapper();

    public ProtocolService(ChannelHandlerContext ctx, String ip, int port, byte[] content) {
        this.ctx = ctx;
        this.ip = ip;
        this.port = port;
        this.content = content;
    }

    @Override
    public void run() {
        processProtocolInfo();
    }

    /**
     * 解析完整的数据报文
     */
    public void processProtocolInfo() {
        // TODO 增加数据处理方法
        log.info(new String(content));
        byte[] reverseContent = EscapeTool.reverseEscapeData(content);

        byte[] cutMsg = new byte[reverseContent.length - 3]; //剪除3个字节 协议头，尾，校验和
        for (int i = 0; i < cutMsg.length; i++) {
            cutMsg[i] = content[i + 1];
        }

        byte linkedAddr = cutMsg[0]; //链路地址  TODO 约定单字节？？？？  是否要判断 bit位
        byte protocolversion = cutMsg[1];  //协议版本号
        byte opType = cutMsg[2]; //操作类型
        byte objectFlag = cutMsg[3]; //对象标识

        //检测器对时响应
        if (objectFlag == 0x02) {
            wrapperFaultData(cutMsg);
        }
        //脉冲数据
        if (objectFlag == 0x08) {
            wrapperPulseData(cutMsg);
        }
        //故障消息
        if (objectFlag == 0x09) {
            wrapperFaultData(cutMsg);
        }
        //周期统计数据
        if (objectFlag == 0x61) {
            wrapperPeriodData(cutMsg);
        }
        //实时统计数据
        if (objectFlag == 0x62) {
            wrapperRealTimeData(cutMsg);
        }
        //异常事件数据
        if (objectFlag == 0x63) {
            wrapperIllegalData(cutMsg);
        }

        try {
            this.ctx.writeAndFlush(
                    new DatagramPacket(
                            Unpooled.copiedBuffer("hello client", CharsetUtil.UTF_8),
                            new InetSocketAddress(ip, port))).sync();
        } catch (InterruptedException e) {
            e.printStackTrace();
        }

    }

    /**
     * 解析并封装故障数据
     *
     * @param msg
     */
    private void wrapperFaultData(byte[] msg) {
        //检测通道数
        int detectionAisleCountL = msg[4] & 0xff;

        //封装每个通道是否故障
        List<AisleFaultData> aisleFaultDataList = new ArrayList<>();
        for (int i = 0; i < detectionAisleCountL; i++) {
            byte[] faultData = new byte[3];
            for (int j = 0; j < 3; j++) {
                faultData[j] = msg[5 + i * 3 + j];
            }
            //检测通道号
            int detectionAisleNumL = faultData[0] & 0xff;

            //通道状态 0:通道正常； 1:通道故障
            int aisleStatusL = faultData[1] & 0xff;

            //故障类型 1：其他异常。（目前检测器暂无异常检测，待后续扩展）
            int faultTypeL = faultData[2] & 0xff;

            AisleFaultData aisleFaultData = new AisleFaultData();
            aisleFaultData.setDetectionAisleNum(detectionAisleNumL);
            aisleFaultData.setAisleStatus(aisleStatusL);
            aisleFaultData.setFaultType(faultTypeL);
            aisleFaultDataList.add(aisleFaultData);
        }
        FaultRadarData faultRadarData = new FaultRadarData();
        faultRadarData.setDetectionAisleCount(detectionAisleCountL);
        faultRadarData.setAisleFaultDataList(aisleFaultDataList);

        try {
            String jsonStr = mapper.writeValueAsString(faultRadarData);
            log.info(jsonStr);
            //TODO 等待入库或者缓存数据 备用
        } catch (JsonProcessingException e) {
            e.printStackTrace();
        }
    }

    /**
     * 解析并封装脉冲数据
     *
     * @param msg
     */
    private void wrapperPulseData(byte[] msg) {
        //检测通道数
        int detectionAisleCountL = msg[4] & 0xff;

        //封装每个通道的脉冲数据
        List<AislePulseData> aislePulseDataList = new ArrayList<>();
        for (int i = 0; i < detectionAisleCountL; i++) {
            byte[] pulseData = new byte[2];
            for (int j = 0; j < 2; j++) {
                pulseData[j] = msg[5 + i * 2 + j];
            }
            //检测通道号
            int detectionAisleNumL = pulseData[0] & 0xff;

            //通道状态 0:车辆离开检测区； 1:车辆进入检测区
            int aisleStatusL = pulseData[1] & 0xff;

            AislePulseData aislePulseData = new AislePulseData();
            aislePulseData.setDetectionAisleNum(detectionAisleNumL);
            aislePulseData.setAisleStatus(aisleStatusL);
            aislePulseDataList.add(aislePulseData);
        }
        PulseRadarData pulseRadarData = new PulseRadarData();
        pulseRadarData.setDetectionAisleCount(detectionAisleCountL);
        pulseRadarData.setPulseDataList(aislePulseDataList);

        try {
            String jsonStr = mapper.writeValueAsString(pulseRadarData);
            log.info(jsonStr);
            //TODO 等待入库或者缓存数据 备用
        } catch (JsonProcessingException e) {
            e.printStackTrace();
        }
    }

    /**
     * 解析并封装异常事件数据
     *
     * @param msg
     */
    private void wrapperIllegalData(byte[] msg) {
        //统计数据生成的本地时间
        byte[] dateTime = new byte[4];
        for (int i = 0; i < 4; i++) {
            dateTime[i] = msg[i + 4];
        }
        int datetimeL = byte4ToInt(dateTime);

        //异常事件个数
        int illegalNumL = msg[8] & 0xff;

        //遍历出异常事件数据包
        List<IllegalInDetailData> illegalInDetailDataList = new ArrayList<>();
        for (int i = 0; i < illegalNumL; i++) {
            //异常事件数据包，去掉保留4位
            byte[] illegalData = new byte[8];
            for (int j = 0; j < 8; j++) {
                illegalData[j] = msg[9 + i * 12 + j];
            }
            //异常事件类型
            int illegalTypeL = illegalData[0] & 0xff;

            //车道编号
            int belongToLaneNoL = illegalData[1] & 0xff;

            //异常事件位置
            byte[] illegalLocation = new byte[4];
            for (int k = 0; k < 4; k++) {
                illegalLocation[k] = illegalData[k + 2];
            }
            float illegalLocationL = Float.intBitsToFloat(byte4ToInt(illegalLocation));

            //车辆速度
            byte[] vehicleSpeed = new byte[2];
            for (int k = 0; k < 2; k++) {
                vehicleSpeed[k] = illegalData[k + 6];
            }
            int vehicleSpeedL = bytes2ToInt(vehicleSpeed);

            IllegalInDetailData illegalInDetailData = new IllegalInDetailData();
            illegalInDetailData.setIllegalType(illegalTypeL);
            illegalInDetailData.setBelongToLaneNo(belongToLaneNoL);
            illegalInDetailData.setIllegalLocation(illegalLocationL);
            illegalInDetailData.setVehicleSpeed(vehicleSpeedL);
            illegalInDetailDataList.add(illegalInDetailData);
        }
        IllegalRadarData illegalRadarData = new IllegalRadarData();
        illegalRadarData.setCreateDateTime(datetimeL);
        illegalRadarData.setIllegalNum(illegalNumL);
        illegalRadarData.setIllegalInDetailDataList(illegalInDetailDataList);
        //处理数据
        try {
            String jsonStr = mapper.writeValueAsString(illegalRadarData);
            log.info(jsonStr);
            //TODO 等待入库或者缓存数据 备用
        } catch (JsonProcessingException e) {
            e.printStackTrace();
        }
    }

    /**
     * 解析并封装周期统计数据
     *
     * @param msg
     */
    private void wrapperPeriodData(byte[] msg) {
        //统计数据生成的本地时间
        byte[] dateTime = new byte[4];
        for (int i = 0; i < 4; i++) {
            dateTime[i] = msg[i + 4];
        }
        int datetimeL = byte4ToInt(dateTime);

        //周期时间统计
        byte[] cycleLength = new byte[2];
        for (int i = 0; i < 2; i++) {
            cycleLength[i] = msg[i + 8];
        }
        int cycleLengthL = bytes2ToInt(cycleLength);

        //总车流量
        byte[] totalVehFlow = new byte[2];
        for (int i = 0; i < 2; i++) {
            totalVehFlow[i] = msg[i + 10];
        }
        int totalVehFlowL = bytes2ToInt(totalVehFlow);

        //检测车道数
        int laneSum = msg[12] & 0xff;

        //检测截面数
        int sectionSum = msg[13] & 0xff;

        //根据车道数，遍历出所有车道数据，单车道占位34字节
        List<PeriodPerLaneData> periodLaneDataList = new ArrayList<PeriodPerLaneData>();
        for (int i = 0; i < laneSum; i++) {
            //周期每条车道的数据包，去掉保留4位
            byte[] laneData = new byte[34 - 4];
            for (int j = 0; j < 30; j++) {
                laneData[j] = msg[14 + 34 * i + j];
            }
            //车道编号
            int laneNoL = laneData[0] & 0xff;

            //车流量
            byte[] vehicleFlow = new byte[2];
            for (int k = 0; k < 2; k++) {
                vehicleFlow[k] = laneData[k + 1];
            }
            int vehicleFlowL = bytes2ToInt(vehicleFlow);

            //平均速度
            byte[] avgSpeed = new byte[2];
            for (int k = 0; k < 2; k++) {
                avgSpeed[k] = laneData[k + 3];
            }
            int avgSpeedL = bytes2ToInt(avgSpeed);

            //最大速度
            byte[] maxSpeed = new byte[2];
            for (int k = 0; k < 2; k++) {
                maxSpeed[k] = laneData[k + 5];
            }
            int maxSpeedL = bytes2ToInt(maxSpeed);

            //85分位值通行速度
            byte[] eightyfiveVehicleSpeed = new byte[2];
            for (int k = 0; k < 2; k++) {
                eightyfiveVehicleSpeed[k] = laneData[k + 7];
            }
            int eightyfiveVehicleSpeedL = bytes2ToInt(eightyfiveVehicleSpeed);

            //排队长度
            byte[] queueLength = new byte[4];
            for (int k = 0; k < 4; k++) {
                queueLength[k] = laneData[k + 9];
            }
            float queueLengthL = Float.intBitsToFloat(byte4ToInt(queueLength));

            //路况——0：畅通 1：缓行 2：拥堵 FE：未知
            int roadConditionL = laneData[13] & 0xff;

            //周期内车辆平均停车次数
            byte[] avgStopNum = new byte[4];
            for (int k = 0; k < 4; k++) {
                avgStopNum[k] = laneData[k + 14];
            }
            float avgStopNumL = Float.intBitsToFloat(byte4ToInt(avgStopNum));

            //周期内车辆平均延误时间
            byte[] avgDelayTime = new byte[4];
            for (int k = 0; k < 4; k++) {
                avgDelayTime[k] = laneData[k + 18];
            }
            float avgDelayTimeL = Float.intBitsToFloat(byte4ToInt(avgDelayTime));

            //周期内车辆的总燃油消耗量
            byte[] fuelConsumption = new byte[4];
            for (int k = 0; k < 4; k++) {
                fuelConsumption[k] = laneData[k + 22];
            }
            float fuelConsumptionL = Float.intBitsToFloat(byte4ToInt(fuelConsumption));

            //周期内车辆的尾气排放总量
            byte[] exhaustGasEmission = new byte[4];
            for (int k = 0; k < 4; k++) {
                exhaustGasEmission[k] = laneData[k + 26];
            }
            float exhaustGasEmissionL = Float.intBitsToFloat(byte4ToInt(exhaustGasEmission));

            //封装周期车道统计数据
            PeriodPerLaneData periodPerLaneData = new PeriodPerLaneData();
            periodPerLaneData.setLaneNo(laneNoL);
            periodPerLaneData.setVehicleFlow(vehicleFlowL);
            periodPerLaneData.setAvgSpeed(avgSpeedL);
            periodPerLaneData.setMaxSpeed(maxSpeedL);
            periodPerLaneData.setEightyfiveVehicleSpeed(eightyfiveVehicleSpeedL);
            periodPerLaneData.setQueueLength(queueLengthL);
            periodPerLaneData.setRoadCondition(roadConditionL);
            periodPerLaneData.setAvgStopNum(avgStopNumL);
            periodPerLaneData.setAvgDelayTime(avgDelayTimeL);
            periodPerLaneData.setFuelConsumption(fuelConsumptionL);
            periodPerLaneData.setExhaustGasEmission(exhaustGasEmissionL);
            periodLaneDataList.add(periodPerLaneData);
        }

        //根据截面数，遍历出所有截面数据，单截面占位29字节
        List<PeriodSectionData> periodSectionDataList = new ArrayList<PeriodSectionData>();
        for (int i = 0; i < sectionSum; i++) {
            //周期每个截面的数据包，去掉保留4位
            byte[] sectionData = new byte[29 - 4];
            for (int j = 0; j < 25; j++) {
                sectionData[j] = msg[14 + 34 * laneSum + 29 * i + j];
            }
            //截面编号
            int sectionNoL = sectionData[0] & 0xff;

            //截面距离
            byte[] sectionDistance = new byte[4];
            for (int k = 0; k < 4; k++) {
                sectionDistance[k] = sectionData[k + 1];
            }
            float sectionDistanceL = Float.intBitsToFloat(byte4ToInt(sectionDistance));

            //截面所在车道编号
            int belongToLaneNoL = sectionData[5] & 0xff;

            //车流量
            byte[] vehicleFlow = new byte[2];
            for (int k = 0; k < 2; k++) {
                vehicleFlow[k] = sectionData[k + 6];
            }
            int vehicleFlowL = bytes2ToInt(vehicleFlow);

            //大型车流量
            byte[] bigVehicleFlow = new byte[2];
            for (int k = 0; k < 2; k++) {
                bigVehicleFlow[k] = sectionData[k + 8];
            }
            int bigVehicleFlowL = bytes2ToInt(bigVehicleFlow);

            //中型车流量
            byte[] middleVehicleFlow = new byte[2];
            for (int k = 0; k < 2; k++) {
                middleVehicleFlow[k] = sectionData[k + 10];
            }
            int middleVehicleFlowL = bytes2ToInt(middleVehicleFlow);

            //小型车流量
            byte[] smallVehicleFlow = new byte[2];
            for (int k = 0; k < 2; k++) {
                smallVehicleFlow[k] = sectionData[k + 12];
            }
            int smallVehicleFlowL = bytes2ToInt(smallVehicleFlow);

            //时间占有率
            int timeRatioL = sectionData[14] & 0xff;

            //平均速度
            byte[] avgSpeed = new byte[2];
            for (int k = 0; k < 2; k++) {
                avgSpeed[k] = sectionData[k + 15];
            }
            int avgSpeedL = bytes2ToInt(avgSpeed);

            //最大速度
            byte[] maxSpeed = new byte[2];
            for (int k = 0; k < 2; k++) {
                maxSpeed[k] = sectionData[k + 17];
            }
            int maxSpeedL = bytes2ToInt(maxSpeed);

            //85分位值通行速度
            byte[] eightyfiveVehicleSpeed = new byte[2];
            for (int k = 0; k < 2; k++) {
                eightyfiveVehicleSpeed[k] = sectionData[k + 19];
            }
            int eightyfiveVehicleSpeedL = bytes2ToInt(eightyfiveVehicleSpeed);

            //平均车辆长度
            int avgVehicleLengthL = sectionData[21] & 0xff;

            //平均车头时距
            int avgVehicleTimeIntervalL = sectionData[22] & 0xff;

            //最大车头时距
            int maxVehicleTimeIntervalL = sectionData[23] & 0xff;

            //85分位值车头时距
            int eightyfiveVehicleTimeIntervalL = sectionData[24] & 0xff;

            PeriodSectionData periodSectionData = new PeriodSectionData();
            periodSectionData.setSectionNo(sectionNoL);
            periodSectionData.setSectionDistance(sectionDistanceL);
            periodSectionData.setBelongToLaneNo(belongToLaneNoL);
            periodSectionData.setVehicleFlow(vehicleFlowL);
            periodSectionData.setBigVehicleFlow(bigVehicleFlowL);
            periodSectionData.setMiddleVehicleFlow(middleVehicleFlowL);
            periodSectionData.setSmallVehicleFlow(smallVehicleFlowL);
            periodSectionData.setTimeRatio(timeRatioL);
            periodSectionData.setAvgSpeed(avgSpeedL);
            periodSectionData.setMaxSpeed(maxSpeedL);
            periodSectionData.setEightyfiveVehicleSpeed(eightyfiveVehicleSpeedL);
            periodSectionData.setAvgVehicleLength(avgVehicleLengthL);
            periodSectionData.setAvgVehicleTimeInterval(avgVehicleTimeIntervalL);
            periodSectionData.setMaxVehicleTimeInterval(maxVehicleTimeIntervalL);
            periodSectionData.setEightyfiveVehicleTimeInterval(eightyfiveVehicleTimeIntervalL);
            periodSectionDataList.add(periodSectionData);
        }

        //封装周期数据实例
        PeriodRadarData periodRadarData = new PeriodRadarData();
        periodRadarData.setCreateDateTime(datetimeL);
        periodRadarData.setCycleLength(cycleLengthL);
        periodRadarData.setTotalVehicleFlow(totalVehFlowL);
        periodRadarData.setLaneSum(laneSum);
        periodRadarData.setSectionSum(sectionSum);
        periodRadarData.setPeriodLaneDataList(periodLaneDataList);
        periodRadarData.setPeriodSectionDataList(periodSectionDataList);

        //处理数据
        try {
            String jsonStr = mapper.writeValueAsString(periodRadarData);
            log.info(jsonStr);
            //TODO 等待入库或者缓存数据 备用
        } catch (JsonProcessingException e) {
            e.printStackTrace();
        }
    }

    /**
     * 解析并封装实时统计数据
     *
     * @param msg
     */
    private void wrapperRealTimeData(byte[] msg) {

        RealTimeRadarData realTimeData = new RealTimeRadarData();
        List<PerLaneData> perLaneDataList = new ArrayList<PerLaneData>();
        byte[] dateTime = new byte[4];
        for (int i = 0; i < 4; i++) {
            dateTime[i] = msg[i + 4];
        }
        int datetimeL = byte4ToInt(dateTime); //统计时间
        byte[] totalVehFlow = new byte[2];
        for (int i = 0; i < 2; i++) {
            totalVehFlow[i] = msg[i + 8];
        }
        int totalVehFlowL = bytes2ToInt(totalVehFlow); //总车流量
        int laneSumL = msg[10] & 0xff; //检测车道数
        //TODO 根据laneSumL车道数遍历出所以车道数据  单车道数据占位37字节
        for (int i = 0; i < laneSumL; i++) {
            byte[] tempbytes = new byte[37 - 4];
            for (int j = 0; j < 33; j++) {  //去掉4个保留位
                tempbytes[j] = msg[37 * i + 11 + j];
            }
            int laneNoL = tempbytes[0] & 0xff; //车道编号

            byte[] vehFlow = new byte[2];
            for (int k = 0; k < 2; k++) {
                vehFlow[k] = tempbytes[k + 1];
            }
            int vehflowL = bytes2ToInt(vehFlow); //车道流量
            int spaceRatioL = tempbytes[3] & 0xff; //空间占有率
            byte[] avgspeed = new byte[2];
            for (int k = 0; k < 2; k++) {
                avgspeed[k] = tempbytes[k + 4];
            }
            int avgspeedL = bytes2ToInt(avgspeed); //平均时速
            int distributionL = tempbytes[6] & 0xff; //分布情况
            byte[] queueLen = new byte[4];
            for (int k = 0; k < 4; k++) {
                queueLen[k] = tempbytes[k + 7];
            }
            float queueLengthL = Float.intBitsToFloat(byte4ToInt(queueLen)); //排队长度
            byte[] vehnum = new byte[2];
            for (int k = 0; k < 2; k++) {
                vehnum[k] = tempbytes[k + 11];
            }
            int queueVehicleNumL = bytes2ToInt(vehnum); //排队车辆数
            byte[] queueLeaderpos = new byte[4];
            for (int k = 0; k < 4; k++) {
                queueLeaderpos[k] = tempbytes[k + 13];
            }
            float queueLeaderposL = Float.intBitsToFloat(byte4ToInt(queueLeaderpos)); //队首位置
            byte[] queueTailpos = new byte[4];
            for (int k = 0; k < 4; k++) {
                queueTailpos[k] = tempbytes[k + 17];
            }
            float queueTailposL = Float.intBitsToFloat(byte4ToInt(queueTailpos)); //队尾位置
            byte[] firstVehpos = new byte[4];
            for (int k = 0; k < 4; k++) {
                firstVehpos[k] = tempbytes[k + 21];
            }
            float firstVehposL = Float.intBitsToFloat(byte4ToInt(firstVehpos)); //头车位置
            byte[] firstVehSpeed = new byte[2];
            for (int k = 0; k < 2; k++) {
                firstVehSpeed[k] = tempbytes[k + 25];
            }
            int firstVehSpeedL = bytes2ToInt(firstVehSpeed); //头车速度
            byte[] tailVehpos = new byte[4];
            for (int k = 0; k < 4; k++) {
                tailVehpos[k] = tempbytes[k + 27];
            }
            float tailVehposL = Float.intBitsToFloat(byte4ToInt(tailVehpos)); //尾车位置
            byte[] tailVehSpeed = new byte[2];
            for (int k = 0; k < 2; k++) {
                tailVehSpeed[k] = tempbytes[k + 31];
            }
            int tailVehSpeedL = bytes2ToInt(tailVehSpeed); //尾车速度

            PerLaneData prdata = new PerLaneData();
            prdata.setLaneNo(laneNoL);
            prdata.setDistribution(distributionL);
            prdata.setVehicleFlow(vehflowL);
            prdata.setAvgSpeed(avgspeedL);
            prdata.setFirstVehiclePos(firstVehposL);
            prdata.setFirstVehicleSpeed(firstVehSpeedL);
            prdata.setSpaceRatio(spaceRatioL);
            prdata.setQueueLeaderPos(queueLeaderposL);
            prdata.setQueueLength(queueLengthL);
            prdata.setQueueTailPos(queueTailposL);
            prdata.setTailVehiclePos(tailVehposL);
            prdata.setTailVehicleSpeed(tailVehSpeedL);
            prdata.setQueueVehicleNum(queueVehicleNumL);
            perLaneDataList.add(prdata);
        }
        realTimeData.setCreateDateTime(datetimeL);
        realTimeData.setTotalVehicleFlow(totalVehFlowL);
        realTimeData.setLaneSum(laneSumL);
        realTimeData.setLaneDataList(perLaneDataList);

        try {
            String jsonStr = mapper.writeValueAsString(realTimeData);
            log.info(jsonStr);
            //TODO 等待入库或者缓存数据 备用
        } catch (JsonProcessingException e) {
            e.printStackTrace();
        }
    }


    /**
     * 将两个字节数组转换成整数
     *
     * @param b
     * @return
     */
    private int bytes2ToInt(byte b[]) {
        int s = 0;
        s = ((b[0] & 0xff) << 8 | (b[1] & 0xff));
        return s;
    }

    /**
     * 将四个字节数组转换成整数
     *
     * @param b
     * @return
     */
    private int byte4ToInt(byte[] b) {
        byte[] a = new byte[4];
        int i = a.length - 1, j = b.length - 1;
        for (; i >= 0; i--, j--) {//从b的尾部(即int值的低位)开始copy数据
            if (j >= 0)
                a[i] = b[j];
            else
                a[i] = 0;//如果b.length不足4,则将高位补0
        }
        int v0 = (a[0] & 0xff) << 24;//&0xff将byte值无差异转成int,避免Java自动类型提升后,会保留高位的符号位
        int v1 = (a[1] & 0xff) << 16;
        int v2 = (a[2] & 0xff) << 8;
        int v3 = (a[3] & 0xff);
        return v0 + v1 + v2 + v3;
    }
}
